package com.juyu.miliao.scheduler.service;

import com.juyu.miliao.common.constant.EnumType;
import com.juyu.miliao.common.netease.NetEaseCloudUserService;
import com.juyu.miliao.common.util.NumberTool;
import com.juyu.miliao.scheduler.dao.mysql.UserInfoDao;
import com.juyu.miliao.scheduler.dao.redis.LineTimeRedisDao;
import com.juyu.miliao.scheduler.domin.Action;
import com.juyu.miliao.scheduler.domin.SendRobot;
import com.juyu.miliao.scheduler.domin.User;
import com.juyu.miliao.scheduler.domin.UserWallet;
import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.Header;
import net.sf.json.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;

/**
 * 线下机器人消息
 * by wbf
 * 2019-05-15 复查慢查询sql 发现已弃用该定时任务
 */
@Component
public class VestRobotMessageScheduler {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserInfoDao userInfoDao;
    @Resource
    private LineTimeRedisDao lineTimeRedisDao;
    @Resource
    private NewUserRobotMessageService newUserRobotMessageService;
    private final Logger logger = LoggerFactory.getLogger(RobotMessageService.class);

//    @Scheduled(fixedDelay = 1000 * 10, initialDelay = 1000 * 15)
    public void scheduler() {
        logger.info("定时任务VestRobotMessage开始：time={}",
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        //获取任务池数据
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries("vestRobotMessageScheduled");
        //获取当前时间戳
        Instant nowTime = Instant.now();
        long timestamp = nowTime.toEpochMilli();// 精确到毫秒
        map.forEach((key, value) -> {
            String str = key.toString();
            str = str.substring(0, str.length() - 4);
            if (Long.parseLong(str) < timestamp) {
                try {
                    //获取参数
                    JSONObject jasonObject = JSONObject.fromObject(value.toString());
                    Map jsonMap = (Map) jasonObject;
                    int userId = Integer.parseInt(jsonMap.get("userId").toString());
                    //用户为空,缓存出错 清除缓存
                    User user = userInfoDao.findUserById(userId);
                    if (user == null) {
                        stringRedisTemplate.opsForHash().delete("vestRobotMessageScheduled", key.toString());
                        return;
                    }
                    //行为id，标记该执行哪个行为，根据list从0开始
                    int actionId = Integer.parseInt(jsonMap.get("actionId").toString());
                    //机器人id，标记该执行哪个机器人的行为，根据list从0开始
                    int sendId = Integer.parseInt(jsonMap.get("sendId").toString());
                    //1:线上  2:线下
                    int isOnline = Integer.parseInt(jsonMap.get("isOnline").toString());
                    //校验完成，开始业务逻辑
                    List<SendRobot> sendRobotList = newUserRobotMessageService.getSendRobot(isOnline);
                    //消息列表为空
                    if (sendRobotList == null || sendRobotList.size() == 0) {
                        return;
                    }
                    //获取机器人
                    SendRobot sendRobot = sendRobotList.get(sendId);
                    //解析行为json
                    sendRobot.setActionList(com.alibaba.fastjson.JSONObject.parseArray(sendRobot.getAction(), Action.class));
                    //获取行为
                    if (sendRobot.getActionList() == null || sendRobot.getActionList().size() == 0) {
                        return;
                    }
                    Action action = sendRobot.getActionList().get(actionId);
                    //钱包是否有金币
//                    UserWallet userWallet = userInfoDao.getUserWalletById(user.getUserId());
                    //该用户在线 且 钱包没有金币
//                    if (lineTimeRedisDao.hasKeyLine(userId + "") && userWallet.getDeposit() == 0) {
                    if (lineTimeRedisDao.hasKeyLine(userId + "")) {
                        //1.文字 2.免费图片 3.语音 4.视频 5.撤销*
                        switch (action.getType()) {
                            case 1:
                                textMessage(userId, sendRobot.getSendUserId(), action.getActionContent());
                                break;
                            case 2:
                                pictureMessage(userId, sendRobot.getSendUserId(), action.getActionContent());
                                break;
                            case 3:
                                speechMessage(userId, sendRobot.getSendUserId(), action.getActionContent());
                                break;
                            case 4:
                                videoMessage(userId, sendRobot.getSendUserId(), action.getActionContent());
                                break;
                            case 5:
                                cancelMessage(userId, sendRobot.getSendUserId());
                                break;
                        }
                    }
                    //如果当前行为是一个机器人的第一个行为，那么为下一个机器人进行初始化存入redis
                    JSONObject json = new JSONObject();
                    if (actionId == 0 && (sendId + 1) < sendRobotList.size()) {
                        json.put("userId", userId);
                        json.put("isOnline", isOnline);
                        json.put("actionId", 0);
                        json.put("sendId", sendId + 1);
                        long timestampSch = LocalDateTime.now().plus(sendRobot.getTimeSpace(), ChronoUnit.SECONDS).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                        stringRedisTemplate.opsForHash().put("vestRobotMessageScheduled", NumberTool.randomInstant(timestampSch), json.toString());
                    }
                    //增加下一个行为
                    if ((actionId + 1) < sendRobot.getActionList().size()) {
                        json.put("userId", userId);
                        json.put("isOnline", isOnline);
                        json.put("actionId", actionId + 1);
                        json.put("sendId", sendId);
                        long timestampSch = LocalDateTime.now().plus(action.getActionTimeSpace(), ChronoUnit.SECONDS).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                        stringRedisTemplate.opsForHash().put("vestRobotMessageScheduled", NumberTool.randomInstant(timestampSch), json.toString());
                    }
                    //删除已发送redis数据
                    stringRedisTemplate.opsForHash().delete("vestRobotMessageScheduled", key.toString());
                } catch (Exception e) {
                    logger.info("机器人消息error：type错误========key={}----value={}-----error{}", key.toString(), value.toString(), e);
                    logger.info("机器人消息error--删除错误key--result={}",
                            stringRedisTemplate.opsForHash().delete("vestRobotMessageScheduled", key.toString()));
                }
            }
        });
        logger.info("定时任务vestRobotMessageScheduled结束：time={}",
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }

    private void textMessage(long userId, long sendUserId, String content) {
        JSONObject body = new JSONObject();
        body.put("msg", content);
        //开发者扩展字段
        JSONObject ext = new JSONObject();
        try {
            logger.info("发送文字-云信：userId={},message={}", userId, body.toString());
            String temp = NetEaseCloudUserService.getSendMsg(userId, sendUserId, EnumType.TEXT_MESSAGE.state, body.toString(), ext.toString(), "");
            if (!temp.substring(temp.indexOf("code") + 6, temp.indexOf("code") + 9).equals("200"))
                logger.error("发送普通消息异常-云信：userId={},message={}", userId, temp);
        } catch (Exception e) {
            logger.error("发送普通消息异常：userId={},error={}", userId, e);
        }
    }

    private void pictureMessage(long userId, long sendUserId, String content) {
        JSONObject body = new JSONObject();
        body.put("name", System.currentTimeMillis());// 图片name
        try {
            URL url = new URL(content);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            InputStream in = conn.getInputStream();
            BufferedImage sourceImg = ImageIO.read(in);
            int w = sourceImg.getWidth();
            int h = sourceImg.getHeight();
            body.put("md5", DigestUtils.md5Hex(in));// 图片文件md5
            body.put("url", content);
            String[] temp = content.split("\\.");
            body.put("ext", temp[temp.length - 1]);
            body.put("w", w);
            body.put("h", h);
            // 根据响应获取文件大小
            body.put("size", conn.getContentLength());
        } catch (Exception e) {
            logger.error("发送图片消息异常-md5转换错误：userId={},error={}", userId, e);
        }
        //开发者扩展字段
        JSONObject ext = new JSONObject();
        ext.put("imagetype", 1);
        try {
            logger.info("发送图片-云信：userId={},message={},ext={}", userId, body.toString(), ext.toString());
            String temp = NetEaseCloudUserService.getSendMsg(userId, sendUserId, EnumType.PICTURE_MESSAGE.state, body.toString(), ext.toString(), "");
            if (!temp.substring(temp.indexOf("code") + 6, temp.indexOf("code") + 9).equals("200"))
                logger.error("发送图片消息异常-云信：userId=" + userId + ",message=" + temp + ",body=" + body.toString());
        } catch (Exception e) {
            logger.error("发送图片消息异常：userId=" + userId, e);
        }
    }

    private void speechMessage(long userId, long sendUserId, String content) {
        JSONObject body = new JSONObject();
        try {
            URL url = new URL(content);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            InputStream in = conn.getInputStream();

            body.put("dur", getMicrosecondLengthForWav(content));
            body.put("md5", DigestUtils.md5Hex(in));
            body.put("url", content);
            body.put("ext", "aac");
            body.put("size", conn.getContentLength());
        } catch (Exception e) {
            logger.error("发送音频消息异常-md5转换错误：content=" + content, e);
        }
        //开发者扩展字段
        JSONObject ext = new JSONObject();
        try {
            logger.info("发送音频-云信：userId={},message={},ext={}", userId, body.toString(), ext.toString());
            String temp = NetEaseCloudUserService.getSendMsg(userId, sendUserId, EnumType.SPEECH_MESSAGE.state, body.toString(), ext.toString(), "");
            if (!temp.substring(temp.indexOf("code") + 6, temp.indexOf("code") + 9).equals("200"))
                logger.error("发送音频消息异常-云信：userId={},message={}", userId, temp);
        } catch (Exception e) {
            logger.error("发送音频消息异常：userId={},error={}", userId, e);
        }
    }

    private void videoMessage(long userId, long sendUserId, String content) {
        //开发者扩展字段
        JSONObject ext = new JSONObject();
        ext.put("videotype", 3); //1:正常视频挂断需回复，2：弹窗视频，3：视频挂断不需回复
        String pushcontent = "向你申请视频通话";
        try {
            // 调用云信接口
            JSONObject body = new JSONObject();
            body.put("msg", content);
            logger.info("发送视频type4-云信：userId={},message={},ext={}", userId, body.toString(), ext.toString() + pushcontent);
            String temp = NetEaseCloudUserService.getSendMsg(userId, sendUserId, EnumType.VIDEO_MESSAGE.state,
                    body.toString(), ext.toString(), pushcontent);
            if (!temp.substring(temp.indexOf("code") + 6, temp.indexOf("code") + 9).equals("200"))
                logger.error("发送视频异常-云信：userId={},message={}", userId, temp);
        } catch (Exception e) {
            logger.error("发送视频异常-系统：userId={},error={}", userId, e);
        }

    }

    private void cancelMessage(long userId, long sendUserId) {
        JSONObject body = new JSONObject();
        body.put("msg", "对方正在输入...");
        //开发者扩展字段
        JSONObject ext = new JSONObject();
        try {
            logger.info("发送文字-云信：userId={},message={}", userId, body.toString());
            String temp = NetEaseCloudUserService.getSendMsg(userId, sendUserId, EnumType.TEXT_MESSAGE.state, body.toString(), ext.toString(), "");
            if (temp.substring(temp.indexOf("code") + 6, temp.indexOf("code") + 9).equals("200")){
                JSONObject jasonObject = JSONObject.fromObject(temp);
                JSONObject jsondata = JSONObject.fromObject(jasonObject.get("data"));
                String recallSendMsg = NetEaseCloudUserService.recallSendMsg(jsondata.get("msgid").toString(),
                        7, sendUserId, userId);
                JSONObject tempJSON = JSONObject.fromObject(recallSendMsg);
                if (!tempJSON.get("code").toString().equals("200"))
                    logger.error("撤回消息回调异常-云信：userId={},message={}", userId, recallSendMsg);
            } else {
                logger.error("撤回消息(发送消息)异常-云信：userId={},message={}", userId, temp);
            }
        } catch (Exception e) {
            logger.error("撤回消息回调异常-云信：userId={},message={}", userId, e);
        }

    }


    /**
     * 获取音频文件时长
     *
     * @param wavFilePath wav文件路径，支持本地和网络HTTP路径
     * @return 时长/微秒，可 /1000000D 得到秒
     * @throws Exception
     */
    public static long getMicrosecondLengthForWav(String wavFilePath) throws Exception {
        URL urlfile = new URL(wavFilePath);
        URLConnection con = urlfile.openConnection();
        int b = con.getContentLength();
        BufferedInputStream bis = new BufferedInputStream(con.getInputStream());
        Bitstream bt = new Bitstream(bis);
        Header h = bt.readFrame();
        if (h == null) {
            return 3420;
        } else {
            return (int) h.total_ms(b);
        }
    }

}
